#include "dbointhread.h"
#include "protocolconversion.h"
#include "macro.h"
#include "dialog.h"
#include "statusoperation.h"
#include "P2P/p2pserver.h"
#include "ONSClient/onsmessenger.h"
#include "datamining.h"
#include <QMessageBox>
#include <QtSql>
//#include <QMutex>
#include <QTimer>
#define DB_Con_Name "ConInThreadDBOReltd"

DBOInThread::DBOInThread(QObject* parent)
    :QObject(parent)
{
    isConnected=false;
    qury=NULL;
    dataMining=NULL;
    timerForDBConnect=new QTimer(this);
    connect(timerForDBConnect,SIGNAL(timeout()),this,SLOT(slotTimerEventDBConnect()));

    //QTimer::singleShot(1000,this,SLOT(slotTestSignal()));
}

void DBOInThread::slotConnectDB()
{
    if(!createConnection(DB_NAME,DB_HOST,DB_USERNAME,
           DB_PWD,QString(DB_Con_Name)))
    {
        emit sigErrorInfo("Connection "DB_Con_Name" failed.\n"
                          +tr("数据库连接失败，程序无法正常运行。请重启程序"));
        exit(11);
    }
    else
        emit sigErrorInfo("connection "DB_Con_Name" success");
}

/***************************************************
在ThreadDBORelated的RUN函数中，初始化DBO类后，会立即调用createConnection函数
建立与数据库的连接.
获得该连接的方法：
QSqlDatabase db=QSqlDatabase::database( QString connectionName);
相应的，要用下面的语句来定义一个QSqlQuery。
QSqlQuery query(QSqlDatabase::database( QString connectionName));
******************************************************/
bool DBOInThread::createConnection(const QString dataBase, const QString host, const QString user,
               const QString passWord, const QString connectionName) //建立一个连接
{
     //plugin的搜索路径增加当前目录下的plugins文件夹。该语句主要为了发布之便。
    //qApp->addLibraryPath(qApp->applicationDirPath () + "/plugins");

    dboConnectionName=connectionName;
    //添加驱动
    QSqlDatabase connectionFromServer=QSqlDatabase::addDatabase(DB_TYPE,connectionName);
    connectionFromServer.setHostName( host);//数据库所在主机的IP
    connectionFromServer.setDatabaseName(dataBase);//操作example数据库
    if(!connectionFromServer.open(user,passWord))
    {
        emit sigErrorInfo("Database Error"+connectionFromServer.lastError().text());
        return false;
    }
    else
    {
        isConnected=true;
        timerForDBConnect->start(MSForDBConnect);
        qury=new QSqlQuery(QSqlDatabase::database(connectionName));
        qury->setForwardOnly(true);
        initTables();
        dataMining=new DataMining(dboConnectionName,qury,this);

        connect(dataMining,SIGNAL(sigInfo(QString)),this,SIGNAL(sigErrorInfo(QString)));

        protConv=new ProtocolConversion(dboConnectionName,this);

          Protocal tempProtocal; bool ok;
        if(! ( qury->exec("select  lenPos, lenSize,    SNPos,  SNSize, "
                   "destPos,destSize,sourcePos, sourceSize, samplePos, CRCSize, "
                    "reservedPos,reservedSize,pkt_TypePos,pkt_TypeSize,typePos,typeSize,header "
                   "from SProtocolTable") ) )    //
            {
                emit sigErrorInfo("Database Error"+connectionFromServer.lastError().text());
            }
        else while(qury->next())//读取协议
        {
           tempProtocal.pLenPos=qury->value(0).toUInt(&ok);  tempProtocal.pLenSize=qury->value(1).toUInt(&ok);
           tempProtocal.pSNPos=qury->value(2).toUInt(&ok);  tempProtocal.pSNSize=qury->value(3).toUInt(&ok);
           tempProtocal.pDestPos=qury->value(4).toUInt(&ok); tempProtocal.pDestSize=qury->value(5).toUInt(&ok);
           tempProtocal.pSourcePos=qury->value(6).toUInt(&ok);tempProtocal.pSourceSize=qury->value(7).toUInt(&ok);
           tempProtocal.pSamplePos=qury->value(8).toUInt(&ok);tempProtocal.pCRCSize=qury->value(9).toUInt(&ok);
           tempProtocal.pReservedPos=qury->value(10).toUInt(&ok); tempProtocal.pReservedSize=qury->value(11).toUInt(&ok);
           tempProtocal.pPkt_TypePos=qury->value(12).toUInt(&ok); tempProtocal.pPkt_TypeSize=qury->value(13).toUInt(&ok);
           tempProtocal.pTypePos=qury->value(14).toUInt(&ok); tempProtocal.pTypeSize=qury->value(15).toUInt(&ok);
            tempProtocal.pHeader=qury->value(16).toByteArray();
           mapHeadProtocal.insert(tempProtocal.pHeader,tempProtocal);
        }
    }

    return true;
}

bool DBOInThread::readProtocolTable(const QByteArray protocalHead)
{
    mapHeadProtocal.remove(protocalHead); //先删除
    Protocal tempProtocal;
    tempProtocal.pHeader=protocalHead;
    bool ok;
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

     if(! ( tempQuery.exec("select  lenPos, lenSize,    SNPos,  SNSize, "
                "destPos,destSize,sourcePos, sourceSize, samplePos, CRCSize, "
                 "reservedPos,reservedSize,pkt_TypePos,pkt_TypeSize,typePos,typeSize "
                "from SProtocolTable where header='"+tempProtocal.pHeader+"' ") ) )    //
         {
            emit sigErrorInfo("Database Error"+tempQuery.lastError().text());
         }
     else if(tempQuery.next())//读取协议
     {
        tempProtocal.pLenPos=tempQuery.value(0).toUInt(&ok);  tempProtocal.pLenSize=tempQuery.value(1).toUInt(&ok);
        tempProtocal.pSNPos=tempQuery.value(2).toUInt(&ok);  tempProtocal.pSNSize=tempQuery.value(3).toUInt(&ok);
        tempProtocal.pDestPos=tempQuery.value(4).toUInt(&ok); tempProtocal.pDestSize=tempQuery.value(5).toUInt(&ok);
        tempProtocal.pSourcePos=tempQuery.value(6).toUInt(&ok);tempProtocal.pSourceSize=tempQuery.value(7).toUInt(&ok);
        tempProtocal.pSamplePos=tempQuery.value(8).toUInt(&ok);tempProtocal.pCRCSize=tempQuery.value(9).toUInt(&ok);
        tempProtocal.pReservedPos=tempQuery.value(10).toUInt(&ok); tempProtocal.pReservedSize=tempQuery.value(11).toUInt(&ok);
        tempProtocal.pPkt_TypePos=tempQuery.value(12).toUInt(&ok); tempProtocal.pPkt_TypeSize=tempQuery.value(13).toUInt(&ok);
        tempProtocal.pTypePos=tempQuery.value(14).toUInt(&ok); tempProtocal.pTypeSize=tempQuery.value(15).toUInt(&ok);

        mapHeadProtocal.insert(tempProtocal.pHeader,tempProtocal);
        return true;
     }
     else
     {
        return false; //没有查到匹配结果，返回false
     }
     return false;
}

QByteArray DBOInThread::slotConvertProtocol(QByteArray appData, QString hostIP, quint16 port, qint64 nodeMAcAddr)
{
/*************************************************
  生成数据包中的源地址
  **********************************************/
    QByteArray baHexAppMac;
    QStringList listIPSeg=hostIP.split('.');
    for(int i=0;i<listIPSeg.length();i++)
    {
        QString ipSeg=listIPSeg.at(i);
        bool ok;
        quint8 ipSegUint=ipSeg.toUShort(&ok,10);
        if(ok)
        {
            baHexAppMac.append(mySetNumHex(ipSegUint,2));
        }
    }
    baHexAppMac=baHexAppMac.rightJustified(8,'0',true);
    baHexAppMac.append(mySetNumHex(port,4));
    baHexAppMac.prepend("0000");
    QByteArray result=protConv->convertionAppToGWStepOne(appData,baHexAppMac,mapHeadProtocal);
    emit sigDataConvertedForGW(result,hostIP,port,nodeMAcAddr,protConv->baLastSNBase10);
    return result;
}

QByteArray DBOInThread::slotCmdAck(QByteArray packet)
{
    bool ok;
    Protocal currentWSNProtocol;
    QByteArray head=packet.mid(0,2).toHex().rightJustified(4,'0',true);
    if(!mapHeadProtocal.contains(head))
        readProtocolTable(head);

    if(!mapHeadProtocal.contains(head))
        return "ERROR:No suitable protocol in WSN found whose head is "+head;
    else
        currentWSNProtocol=mapHeadProtocal.value(head);

    /************************解析出App的IP和UDP端口************************/
    QByteArray baDestMac=packet.mid(currentWSNProtocol.pDestPos/8,currentWSNProtocol.pDestSize/8);
    QByteArray appIP;
    for(int i=IPPosByteInAppMac;i<IPPosByteInAppMac+4;i++)
    {
        bool ok;
        appIP.append(QByteArray::number(baDestMac.mid(i,1).toHex().toUShort(&ok,16)));
        appIP.append('.');
    }
    appIP.chop(1);
    quint16 appPort=baDestMac.mid(UDPPortPosByteInAppMac,2).toHex().toUInt(&ok,16);


    QByteArray result=protConv->convertionGWToAppStepOne(packet,currentWSNProtocol);
    emit sigCmdAckToApp(result,appIP,appPort);
    return result;
}

void  DBOInThread::slotStoreVideo(QByteArray data, qint64 nodeMacAddr, quint8 SN,
      QList<QString> *tableNameList, QString *tableNamePrefix, QList<qint64> *newMacList)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    bool ok;
    if(data.size()<=2)
        return;
    quint8 sensorID=data.mid(0,1).toHex().toUShort(&ok,16);

    data.remove(0,1); //去掉第一个字节sensorID

      int indexOfTableName=tableNameList->indexOf(*tableNamePrefix+QString::number(nodeMacAddr,10));
      //用于标识有没有为非海康视频新建了一张表格。海康视频新建表格后，会有另外的特殊处理。
      bool newTableForNonHik=false;
      if(indexOfTableName<0) //not exist
     {
         createMultiTable(nodeMacAddr,sensorID,tableNameList,tableNamePrefix);
         if(sensorID!=11)
             newTableForNonHik=true;
         indexOfTableName=tableNameList->indexOf(*tableNamePrefix+QString::number(nodeMacAddr,10));
      }

     if(indexOfTableName>=0)
     {
         QString tableName=tableNameList->at(indexOfTableName);
         if(tableName.isEmpty()||data.size()<20) //表名为空或者数据过小
             return;

         //只有MySQL数据库的MyISAM引擎才支持“insert delayed”
         //所以需要先判断是不是MySQL数据库。另外，视频的存储引擎应当选用MyISAM，以支持“insert delayed”
         QString delayedStr="";
         QString strDBType=DB_TYPE;
         if(strDBType.toUpper().contains("MYSQL"))
             delayedStr="delayed";

            tempQuery.prepare( "INSERT "+delayedStr+" INTO "+tableName+" (SN,NodeMacAddress,SensorID,SensorData,BeginEnd) "
                           "VALUES (:SN,:nodeMacAddr,:SensorID,:SensorData,:BeginEnd)" );
            tempQuery.bindValue(":SN", SN);tempQuery.bindValue(":nodeMacAddr", nodeMacAddr);

            tempQuery.bindValue(":SensorID", sensorID);
            tempQuery.bindValue(":SensorData", data);

            if(newMacList->contains(nodeMacAddr)||newTableForNonHik==true)
            {
                if(!(sensorID==11&&data.size()>MaxSizeBeginVideo)) //海康，第一帧大于最大起始帧大小的情况
                   tempQuery.bindValue(":BeginEnd", QString("b").toLatin1());
                else
                    tempQuery.bindValue(":BeginEnd", '0');
                newMacList->removeOne(nodeMacAddr);
            }
            else
                 tempQuery.bindValue(":BeginEnd", '0');


            if(!(tempQuery.exec()))
            {
                emit sigErrorInfo("insert multimedia fail"+tempQuery.lastError().text());
            }
        }
     else
         emit sigErrorInfo("No suitable table for video found");

}

/*******建立一张多媒体数据表，并在多媒体数据索引表中记录相关信息*********/
bool DBOInThread::createMultiTable(qint64 nodeMacAddr, quint8 sensorID,
         QList<QString> *tableNameList, QString *tableNamePrefix)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    emit sigErrorInfo("Creating multiTable");
    QString tableName;
    tableName=*tableNamePrefix+QString::number(nodeMacAddr,10);
#ifdef ANDROID   //使用SQLite数据库
    if(tempQuery.exec("create table "+tableName+
            " (DateTime timestamp not null default current_timestamp,"
            "SN smallint ,"
            "NodeMacAddress bigint ,"
            "SensorID smallint,"
            "SensorData BLOB not null,"
            "BeginEnd char(1),index using BTREE(BeginEnd),"
            "ID int  not null primary key autoincrement"
            ")") )
#else   //MySQL
    if(tempQuery.exec("create table "+tableName+
            " (DateTime timestamp not null default current_timestamp,"
            "SN smallint ,"
            "NodeMacAddress bigint ,"
            "SensorID smallint,"
            "SensorData BLOB not null,"
            "BeginEnd char(1),index using BTREE(BeginEnd),"
            "ID int  not null primary key auto_increment"
            ") engine=myisam") )
#endif
    {
        tableNameList->append(tableName);

        //((WeatherStation*)parent())->myP2pServer->addVideoSource(
          //      QHostAddress(aServerIP),aServerPort,nodeMacAddr,sensorID);

        QSqlQuery tempQuery2(QSqlDatabase::database(dboConnectionName));

        if(!tempQuery2.exec("insert into multidataindex (DateTimeStart,NodeMacAddr,TableName,SensorID) values("+
           QDateTime::currentDateTime().toString("yyyyMMddhhmmss")+","+QString::number(nodeMacAddr,10)+",'"+tableName+"',"
           +QString::number(sensorID)+")") )
            emit sigErrorInfo("insert multidataindex fail! check the createMultiTable()"+tempQuery2.lastError().text());

        QTime currentTime=QTime::currentTime();
        int timeTo;
        timeTo=currentTime.msecsTo(QTime(0,0,5,0));
        if(timeTo>0&&sensorID==11) //只有海康视频才需要如下处理
        {
            QDate yestoday=QDateTime::currentDateTime().addSecs(-3600).date(); //this should be yestoday
            QString yesTableNamePrefix=yestoday.toString("'multi'yyyy_MM_dd_'mac'").toLatin1();
            QString yesTableName=yesTableNamePrefix+QString::number(nodeMacAddr,10);

            QSqlQuery tempQuery3(QSqlDatabase::database(dboConnectionName));

            if(tempQuery3.exec("select DateTime from "+yesTableName+" where ID="
                            "(select max(ID) from "+yesTableName+" )"))
            {
                if(tempQuery3.next())
                {
                    QDateTime lastDateTime=tempQuery3.value(0).toDateTime();
                    int gap=lastDateTime.secsTo(QDateTime::currentDateTime());
                    if(gap<5&&gap>=0) //data is continuous
                    {
                        QSqlQuery tempQuery4(QSqlDatabase::database(dboConnectionName));

                        if(tempQuery4.exec("select max(ID),SensorData from "+yesTableName+" where beginend='b' ") )
                        {
                            bool ok;
                            if(tempQuery4.next())
                            {
                                qint32 id=tempQuery4.value(0).toUInt(&ok);
                                QByteArray sensData=tempQuery4.value(1).toByteArray();
                                if(sensData.size()>MaxSizeBeginVideo)
                                    return true; //不是开始帧，去除

                                QSqlQuery tempQuery5(QSqlDatabase::database(dboConnectionName));

                                if(!tempQuery5.exec("insert into "+tableName+" (SN,NodeMacAddress,SensorID,SensorData,BeginEnd) "
                                        "select SN,NodeMacAddress,SensorID,SensorData,BeginEnd from "+yesTableName+" where "
                                               "ID="+QString::number(id,10)))
                                    emit sigErrorInfo("insert begin data failed in createMultiTable. "+
                                               tempQuery5.lastError().text());
                                else
                                {
                                    if(!tempQuery5.exec("update "+tableName+" set DateTime="+QDateTime::currentDateTime().toString("yyyyMMddhhmmss")+
                                                    " where beginend='b' ") )
                                        emit sigErrorInfo("udpate datetime fail in createMultiTable()"+tempQuery5.lastError().text());
                                }
                            }
                        }
                        else
                            qDebug()<<"select max(ID) from yesTableName fail. check createMultiTable"<<tempQuery4.lastError();
                    }

                }
            }
            else
                qDebug()<<"select DateTime from yesTableName fail"<<tempQuery3.lastError();
        }
        emit sigErrorInfo(" multiTable created");
        return true;
    }
    else
    {
        emit sigErrorInfo("Create multiTable failed. "+tempQuery.lastError().text());
        return false;
    }
}

void DBOInThread::slotRegNode(qint64 nodeMacAddr, QByteArray nodeName, qint8 nodeOnWork, QByteArray nodeV4IP,
                  quint16 nodeV4Port, QByteArray nodeType, QByteArray protocHead, qint8 nodeOccupied)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    emit sigErrorInfo("INFOR:Begin to register node");

    insertLog(tr("一个节点与服务器建立了连接，"
          "节点的mac地址是"+QByteArray::number(nodeMacAddr,10)));

    if(!tempQuery.exec("select NodeName from NodeAddressMap where NodeMacAddress="+QByteArray::number(nodeMacAddr,10)))
    {
        emit sigErrorInfo("ERROR:Fail to select * from NodeAddressMap in DBOInThread::slotRegNode."+tempQuery.lastError().text());
    }
    else if(tempQuery.next()) //已经注册过节点
    {
        QSqlQuery tempQuery2(QSqlDatabase::database(dboConnectionName));

        qint64 mask= Q_INT64_C(0x00ffffffffffffff);
        //由于有虚拟节点的概念，所以需要计算低7字节的地址
        qint64 subNodeAddr=nodeMacAddr&mask;

        if(tempQuery2.exec("update NodeAddressMap set NodeV4IP='"+nodeV4IP+"', "
                      "NodeV4Port="+QString::number(nodeV4Port,10)+",NodeOnWork=1,NodeOccupied=0 "
             "where (NodeMacAddress&0x00ffffffffffffff)="+QString::number(subNodeAddr,10)) )
        {

        }
        else
         emit sigErrorInfo("ERROR:Fail to update nodeaddressmap in slotRegNode"+tempQuery2.lastError().text());
    }
    else   //没有注册过节点
    {
        QSqlQuery tempQuery2(QSqlDatabase::database(dboConnectionName));

        if(!tempQuery2.exec("insert into NodeAddressMap (NodeMacAddress,NodeName,NodeOnWork,NodeV4IP,NodeV4Port,"
                      "NodeType,ProtocHead,NodeOccupied) values("+QByteArray::number(nodeMacAddr,10)+",'"+nodeName+"',"+
                      QByteArray::number(nodeOnWork,10)+",'"+nodeV4IP+"',"+QByteArray::number(nodeV4Port,10)+",'"+nodeType+
                "','"+protocHead+"',"+QByteArray::number(nodeOccupied,10)+")"))
        {
            emit sigErrorInfo("ERROR:Fail to register node in DBOInThread::slotRegNode."+tempQuery2.lastError().text());
        }
    }

/*
    if( qury->exec("update NodeSensorMap set SensorOnWork=1 where "
                        " NodeMacAddress="+QString::number(nodeMacAddr,10)))
    {
       qDebug()<<"NodeSensorMap set successfully in doWithMac()";
       //在addrSocketMap表中插入mac与socket的映射关系
    }
    else
        emit sigErrorInfo("NodeSensorMap set fail in slotRegNode()"+qury->lastError().text());
*/
    if(tempQuery.exec("select NodeName,NodeType from NodeAddressMap "
         " where NodeMacAddress="+QString::number(nodeMacAddr,10)) )
    {
        if(tempQuery.next())
        {
            QString sensorType;

            QByteArray nodeName=tempQuery.value(0).toByteArray();
            QString nodeType=tempQuery.value(1).toByteArray();

            if(nodeType.toUpper()=="ARM")
                sensorType="video";
            else
                sensorType="sensor";

            emit sigAddNode(nodeMacAddr,nodeName);
            emit sigSendONSMesg(nodeName,sensorType,OBJ_OWNER,OBJ_LOC,"Update",QString::number(nodeMacAddr,10),true,"");

        }
        else
            emit sigErrorInfo("NodeSensorMap set fail in doWithMac()"+tempQuery.lastError().text());
    }

}

void DBOInThread::slotRegSensorMore(qint64 nodeMacAddr, qint16 sensorID, qint8 sensorOnWork, qint8 dataLen, QByteArray expre)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    if(!tempQuery.exec("select NodeMacAddress from NodeSensorMap where NodeMacAddress="+QByteArray::number(nodeMacAddr,10)+" and SensorID="+
                   QByteArray::number(sensorID,10)))
    {
        emit sigErrorInfo("ERROR:Fail to select NodeMacAddress from NodeSensorMap in DBOInThread::slotRegSensor."+tempQuery.lastError().text());
        qDebug()<<"ERROR:Fail to select NodeMacAddress from NodeSensorMap in DBOInThread::slotRegSensorMore."+tempQuery.lastError().text();
    }
    else if(!tempQuery.next()) //没注册过
    {
        QSqlQuery tempQuery2(QSqlDatabase::database(dboConnectionName));

        if(!tempQuery2.exec("insert into NodeSensorMap (NodeMacAddress,SensorID,DataLength,Expre,SensorOnWork) "
                  " values("+QByteArray::number(nodeMacAddr,10)+","+QByteArray::number(sensorID,10)+","+
                  QByteArray::number(dataLen,10)+",'"+expre+"',"+QByteArray::number(sensorOnWork,10)+")"))
        {
            emit sigErrorInfo("ERROR:Fail to register sensors in DBOInThread::slotRegSensorMore."+tempQuery2.lastError().text());
            qDebug()<<"ERROR:Fail to register sensors in DBOInThread::slotRegSensorMore."+tempQuery2.lastError().text();
        }
    }
    else
        emit sigErrorInfo("Registered before");


    if(tempQuery.exec("update NodeSensorMap set SensorOnWork=1 "
         "where NodeMacAddress="+QString::number(nodeMacAddr,10)+
         " and SensorID="+QString::number(sensorID,10)) )
    {

    }
    else
    {
        emit sigErrorInfo("ERROR:Fail to update nodesensormap in DBOInThread::slotRegSensorMore."+tempQuery.lastError().text());
        qDebug()<<"fail in DBOInthread::slotregensormore"<<tempQuery.lastError();
    }

}

void DBOInThread::slotRegSensor(qint64 nodeMacAddr, qint16 sensorID, qint8 sensorOnWork)
{
    emit sigErrorInfo(tr("在slotRegSensor中"));
    QByteArray defaultExpre;
    qint8 defaultLen;
    emit sigErrorInfo("INFO: begin to register. Mac:"+QByteArray::number(nodeMacAddr)+" SensorID:"+QByteArray::number(sensorID));
     emit sigAddVideoSource(aServerIP,aServerPort,nodeMacAddr,sensorID);
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    if(!tempQuery.exec("select DefaultLength,DefaultExpre from typemap where SensorID="+QByteArray::number(sensorID,10)))
    {
        emit sigErrorInfo("ERROR:Fail to select defaultlength and DefaultExpre in DBOInThread::slotRegSensor. "+tempQuery.lastError().text());
        qDebug()<<"ERROR:Fail to select defaultlength and DefaultExpre in DBOInThread::slotRegSensor. "+tempQuery.lastError().text();
        return;
    }
    else if(tempQuery.next()&&!tempQuery.value(0).isNull())
    {
        defaultLen=tempQuery.value(0).toInt();
        defaultExpre=tempQuery.value(1).toByteArray();
        slotRegSensorMore(nodeMacAddr,sensorID,sensorOnWork,defaultLen,defaultExpre);
    }
    else
    {
        defaultLen=2;
        defaultExpre=""; //表示表达式缺失。由人工处理
        slotRegSensorMore(nodeMacAddr,sensorID,sensorOnWork,defaultLen,defaultExpre);
        emit sigErrorInfo("WARNING: No defaultlength and DefaultExpre Found. in DBOInThread::slotRegSensor");
    }
}

void DBOInThread::slotUnRegSensor(qint64 nodeMacAddr, qint16 sensorID, qint8 sensorOnWork)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    if(tempQuery.exec("update NodeSensorMap set SensorOnWork="+QByteArray::number(sensorOnWork,10)+
         " where NodeMacAddress="+QString::number(nodeMacAddr,10)+
         " and SensorID="+QString::number(sensorID,10)) )
    {

    }
    else
    {
        emit sigErrorInfo("ERROR:Fail to update nodesensormap in DBOInThread::slotUnRegSensor."+tempQuery.lastError().text());
        qDebug()<<"fail in DBOInthread::slotUnRegSensor"<<tempQuery.lastError();
    }
}

void DBOInThread::slotUnRegNode(qint64 nodeSubMacAddr)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

   tempQuery.exec("insert into Log(issue) values('"+tr("若干个节点与服务器断开了连接，"
                "节点的后7位地址是"+QByteArray::number(nodeSubMacAddr,10))+"')");

    if(tempQuery.exec("update NodeAddressMap set NodeV4IP='',"
         "NodeV4Port=0,NodeOnWork=0,NodeOccupied=0 "
         "where (NodeMacAddress&0x00ffffffffffffff)="+QString::number(nodeSubMacAddr,10)) )
    {
        //删除ONS的记录
        if(tempQuery.exec("select NodeName,NodeType from NodeAddressMap "
             " where (NodeMacAddress&0x00ffffffffffffff)="+QString::number(nodeSubMacAddr,10)) )
        {
            while(tempQuery.next())
            {
                QString sensorType;

                QByteArray nodeName=tempQuery.value(0).toByteArray();
                emit sigDeleteNode(nodeSubMacAddr,nodeName);

                QString nodeType=tempQuery.value(1).toByteArray();
                if(nodeType.toUpper()=="ARM")
                    sensorType="video";
                else
                    sensorType="sensor";
                emit sigSendONSMesg(nodeName,sensorType,OBJ_OWNER,OBJ_LOC,"Delete",QString::number(nodeSubMacAddr,10),true,"");

            }
        }
        else
            emit sigErrorInfo("ERROR: fail in DBOInThread::slotUnRegNode."+tempQuery.lastError().text());
    }
    else
        emit sigErrorInfo("ERROR: fail in DBOInThread::slotUnRegNode."+tempQuery.lastError().text());


    if( tempQuery.exec("update NodeSensorMap set SensorOnWork=0 where "
                        " (NodeMacAddress&0x00ffffffffffffff)="+QString::number(nodeSubMacAddr,10))  )
    {
       qDebug()<<"NodeSensorMap reset successfully in doWithMac()";
    }
    else
        emit sigErrorInfo("ERROR: fail in DBOInThread::slotUnRegNode."+tempQuery.lastError().text());


    if(tempQuery.exec("delete from topologytree where (NodeMacAddr&0x00ffffffffffffff)="+
                       QString::number(nodeSubMacAddr,10) ) )
    {
        qDebug()<<"topologyTree updated successfully";
    }
    else
        emit sigErrorInfo("ERROR: fail in DBOInThread::slotUnRegNode."+tempQuery.lastError().text());
}

void DBOInThread::slotPinQuery(qint64 nodeMacAddr)
{
    qint64 subNodeAddr;
    qint64 mask= Q_INT64_C(0x00ffffffffffffff);

    //由于有虚拟节点的概念，所以需要计算低7字节的地址
    subNodeAddr=nodeMacAddr&mask;
    QByteArray dataGramHex;
    emit sigErrorInfo("来自slotPinQUery()的消息：节点查询管脚连接信息，它的低7位地址是："+QByteArray::number(subNodeAddr,16));
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    if(tempQuery.exec("select SensorID,Pins,NodeMacAddress from NodeSensorMap where (NodeMacAddress&0x00ffffffffffffff)="
               +QByteArray::number(subNodeAddr)))
    {
        qint16 sensorID;
        quint8 SN=0;
        qint64 pinNumber,macAdd;
        QByteArray temp;

        while(tempQuery.next())
        {
            dataGramHex="aa4402";
            sensorID=tempQuery.value(0).toInt();
            if(sensorID==0xff) //认为传感器类型不应当是ff
                continue;
            pinNumber=tempQuery.value(1).toLongLong();
            macAdd=tempQuery.value(2).toLongLong();
            temp=temp.setNum(macAdd,16).rightJustified(16,'0',true);
            dataGramHex.append(temp);
            dataGramHex.append("8888888888888888");
             temp=temp.setNum(SN,16).rightJustified(2,'0',true);
            dataGramHex.append(temp);
             temp=temp.setNum(32,16).rightJustified(4,'0',true); //Len
            dataGramHex.append(temp);
             temp=temp.setNum(PktSensorInfo,16).rightJustified(2,'0',true);
            dataGramHex.append(temp); //Pkt_Type
            dataGramHex.append("01"); //Reserved
             temp=temp.setNum(sensorID,16).rightJustified(2,'0',true); //SensorType
            dataGramHex.append(temp);
             temp=temp.setNum(SensorInfoPins,16).rightJustified(2,'0',true);//DataType
            dataGramHex.append(temp);
             temp=temp.setNum(pinNumber,16).rightJustified(16,'0',true); //data
            dataGramHex.append(temp);
            dataGramHex=QByteArray::fromHex(dataGramHex);
            dataGramHex.append(QByteArray::fromHex(getCRC16Hex(dataGramHex.mid(2,dataGramHex.size()-2))));
            emit sigErrorInfo("INFO: 对节点的管脚信息的回复是： "+QByteArray::number(nodeMacAddr)+" is "+dataGramHex);
            emit sigPinQueryFromNodeDone(dataGramHex,nodeMacAddr);
            SN++;
        }
     }
    else
        emit sigErrorInfo("DataBase ERROR: "+tempQuery.lastError().text());

}

void DBOInThread::slotTimerEventDBConnect()
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    tempQuery.exec("select 1");
}

bool    DBOInThread::insertLog(QString issue)
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

    if(tempQuery.exec("insert into Log(issue) values('"+issue+
           "')"))
        return true;
    else
    {
        emit sigErrorInfo("Error:insert Log fail in DBOInThread::insertLog()"+
                             tempQuery.lastError().text());
        return false;
    }
}

/*
 初始化表格
 */
void DBOInThread::initTables()
{
    QSqlQuery tempQuery(QSqlDatabase::database(dboConnectionName));

     if( tempQuery.exec("truncate AliveCmdRec")  ) //清空活动命令记录表
     {

     }
     if(tempQuery.exec("update NodeAddressMap set NodeV4IP='',NodeV4Port=0,NodeOnWork=0,NodeOccupied=0 ")  ) //设备的IP信息清零
     {

     }
     else
         emit sigErrorInfo(tempQuery.lastError().text());

     if(tempQuery.exec("update NodeSensorMap set SensorOnWork=0")  )
     {

     }

     if(tempQuery.exec("truncate topologytree")  ) //清空活动命令记录表
     {

     }
}

DBOInThread::~DBOInThread()
{
    initTables();
    delete protConv;
    QSqlDatabase db=QSqlDatabase::database(dboConnectionName);
    if(db.isOpen())
    {
        db.close();
    }
    if(!db.isOpen())
    {
        //qDebug()<<"connection "+dboConnectionName+" disconnected";
    }
}

void DBOInThread::slotTestSignal()
{
    //emit sigAddVideoSource("127.0.0.1",6789,11111,11);
}

void DBOInThread::slotRemoveOneInControllingMacList(QString macStr)
{
    protConv->controllingMacList.removeOne(macStr);
}
